#import "PaintDocView.h"
#import "PaintLabParams.h"

#import <appkit/Application.h>
#import <appkit/Bitmap.h>
#import <appkit/Window.h>
#import <dpsclient/wraps.h>

@implementation PaintDocView


+newFrame:(NXRect *)tF
{
	NXRect docRect;
	
	// Create the new view
	self = [super newFrame:tF];
	
	// Initialize parameters
	brushSize = 1;			
	brushShape = ROUND_BRUSH;
	paintColor = NX_BLACK;
	
	// Create and initialize the bitmaps
	paintDropBitmap = [[Bitmap newSize:BITMAP_SIZE :BITMAP_SIZE
			          type:NX_UNIQUEBITMAP] setFlip:NO];
	[self updatePaintDropBitmap];
	docBitmap = [[Bitmap newSize:DOC_WIDTH :DOC_HEIGHT
			    type:NX_NOALPHABITMAP] setFlip:NO];
	NXSetRect(&docRect, 0.0, 0.0, DOC_WIDTH, DOC_HEIGHT);
	[docBitmap lockFocus];
	NXEraseRect(&docRect);
	[docBitmap unlockFocus];
	
	return self;
}




- clear
{
	NXRect rect;
	
	// Clear the screen
	[self lockFocus];
	NXEraseRect(&bounds);
	[self unlockFocus];

	// Clear the doc bitmap
	NXSetRect(&rect, 0.0, 0.0, DOC_WIDTH, DOC_HEIGHT);
	[docBitmap lockFocus];
	NXEraseRect(&rect);
	[docBitmap unlockFocus];
        return self;
}



- setDocBrushShape:(int)newBrushShape
{
	brushShape = newBrushShape;
	[self updatePaintDropBitmap];
	return self;
}


- setDocBrushSize:(float)newBrushSize
{
	brushSize = newBrushSize;
	[self updatePaintDropBitmap];
	return self;
}

- setDocPaintColor:(float)newPaintColor
{
	paintColor = newPaintColor;
	[self updatePaintDropBitmap];
	return self;
}




/*
 * The paintdrop bitmap is a small bitmap which contains the
 * image of a single drop of paint, based on the current color,
 * brush size, and brush shape.
 *
 */

- updatePaintDropBitmap
{
	[paintDropBitmap lockFocus];
	PSsetstrokeadjust (NO);
        PScompositerect (0.0, 0.0, BITMAP_SIZE, BITMAP_SIZE, NX_CLEAR);
	PSsetalpha(1.0);       // We want opaque brushes
	PSsetgray(paintColor);
	if (brushShape == SQUARE_BRUSH) {
		PSrectfill (0.0, 0.0, brushSize, brushSize);
        } else if (brushShape == ROUND_BRUSH) {
		PSnewpath();
		PSarc(brushSize/2.0, brushSize/2.0, 
		      (brushSize/2.0)-0.5,  // a fudge factor
		      0.0, 360.0);
		PSclosepath();	
		PSfill();
	}
	[paintDropBitmap unlockFocus];

	return self;
}




/*
 * When the mouse button goes down, draw a paintdrop.  Then grab
 * and paint all mouse-dragged events until the button goes up
 * again.
 *
 */
 
#define DRAG_OR_UP_MASK     NX_MOUSEDRAGGEDMASK|NX_MOUSEUPMASK
- mouseDown:(NXEvent *) theEvent
{
	int old_event_mask;
	NXEvent *latestEvent;
	
	[self paintOneDrop:&theEvent->location];
	old_event_mask = [window eventMask];
	// Enable mouse-dragged and mouse-up events.
	[window addToEventMask:DRAG_OR_UP_MASK];
	while (YES) {
		latestEvent = [NXApp getNextEvent:DRAG_OR_UP_MASK];
		if (latestEvent->type == NX_MOUSEUP) break;
		[self autoscroll:latestEvent];
		[self paintOneDrop:&latestEvent->location];
	}
	// Re-disable mouse-dragged and mouse-up events.
	[window setEventMask:old_event_mask];
		
	return self;
}




/*
 * Paints to the view and the docBitmap.  The purpose of the
 * docBitmap is to provide a way for drawSelf:: to know how
 * to repaint broken parts of the screen.
 *
 */

- paintOneDrop:(NXPoint *) cursorLocation
{
	NXPoint dest;
	
	// Convert from window's coords to self's.
	[self convertPoint:cursorLocation fromView:nil];
	
	// Center paintdrop on cursor's hotspot.
	dest.x = cursorLocation->x - brushSize/2.0;
	dest.y = cursorLocation->y - brushSize/2.0;
	
	// Draw paintdrop in docView.
	[self lockFocus];
	[paintDropBitmap composite:NX_SOVER toPoint:&dest];
	[[self window] flushWindow];
	[self unlockFocus];
	
	// Draw paintdrop in bitmap.
	[docBitmap lockFocus];
	[paintDropBitmap composite:NX_SOVER toPoint:&dest];
	[docBitmap unlockFocus];
	
	return self;
}
	


-drawSelf:(NXRect *)r:(int) count
{
	NXPoint dest;
	NXRect source;
	int i;
	
	for (i=((count == 3) ? 1 : 0); i<count; i++) {
		source = *r;
		[docBitmap composite:NX_COPY
			   fromRect:&source
			   toPoint:&r->origin];
		r++;
	}

	return self;
}





@end
